package jmh;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;

/**
 * 使用JMH测试ArrayList、LinkedList的性能——add
 * 最新的1.33测试失败：OOM，使用1.19才可以测试
 * 测试类中没有 @Benchmark 注解的方法，会发生异常
 * 预热 还可以使用 @Warmup 适用 类 方法
 * 度量 还可以使用 @Measurement 适用 类 方法
 * @author ben
 * @date 2021-09-23 20:31:23 CST
 */
// 还有更多模式，还可以组合模式
@BenchmarkMode(Mode.AverageTime)
// 还支持更细的时间
@OutputTimeUnit(TimeUnit.MICROSECONDS)
// 还有更多
@State(Scope.Thread)
public class Jmh1 {

	// java.lang.OutOfMemoryError: Java heap space
	// at java.util.Arrays.copyOf(Arrays.java:3181)
	public final static String DATA = "DUMMY DATA";
//	public final static String DATA = "D";
//	public final static String DATA = "";
	
	private List<String> arrayList;
	private List<String> linkedList;
	
	public static int cnt = 0;
	
	@Setup(Level.Iteration)
	public void setUp() {
		arrayList = new ArrayList<String>();
		linkedList = new LinkedList<String>();
	}
	
	// 基准测试方法使用
	@Benchmark
	public List<String> arrayListAdd() {
		cnt++;
		try {
			this.arrayList.add(DATA);
		} catch (OutOfMemoryError e) {
			// cnt=157704908, size=157704907
			System.out.println("cnt=" + cnt + ", size=" + this.arrayList.size());
			throw e;
		}
		return this.arrayList;
	}
	
	@Benchmark
	public List<String> linkedListAdd() {
		this.linkedList.add(DATA);
		return linkedList;
	}
	
	public static void main(String[] args) throws RunnerException {
		final Options opts = new OptionsBuilder()
				.include(Jmh1.class.getSimpleName())
				.forks(1)
				// 预热：使代码的执行经历过了类的早起优化、JVM运行期编译、JIT优化
				.warmupIterations(10)
				.warmupTime(TimeValue.seconds(1L))
				// 真正的度量操作
				.measurementIterations(10)
				.measurementTime(TimeValue.seconds(1L))
				.build();
		new Runner(opts).run();
	}

}
